import numpy as np
from sklearn.decomposition import PCA
import pandas as pd

#总结：SVD降维并不是降得矩阵大小，若矩阵大小都变了，你还能分析么？
#降的“维”，我理解上更像是语音或者图像信号。把原来纷繁复杂的信号进行拆解，
# 剔除掉一些引入的噪声，剩下原有信号中的出成分。

x = np.array([[1, 1, 1], [0, 0, -1], [1, -1, 1], [-1, 1, 0]]).T
U, s, V = np.linalg.svd(x)

def calc_k():
    #'''确定k值：前k个奇异值的平方和占比 >=percentage, 求满足此条件的最小k值
    # :return 满足阈值percentage的最小k值
    percentage = 0.9
    k = 0
    # 用户数据矩阵的奇异值序列的平方和
    total = sum(np.square(s))
    svss = 0  # 奇异值平方和 singular values square sum
    for i in range(np.shape(s)[0]):
        svss += np.square(s[i])
        if (svss / total) >= percentage:
            k = i + 1
            break
    return k


def buildSD(k):
    #'''构建由奇异值组成的对角矩阵
    #:param k,根据奇异值开放和的占比阈值计算出来的k值
    #:return 由k个前奇异值组成的对角矩阵

    # 方法1：用数组乘方法
    #np.eye()返回一个对角线diagonal上全是1，而其他位置全为0的一个二维数组
    SD = np.eye(k) * s[:k]
    return SD


if __name__ == "__main__":
        # SVD算法
    # 第1步：奇异值分解
    x = np.array([[1, 1, 1], [0, 0, -1], [1, -1, 1], [-1, 1, 0]]).T
    U,s,V = np.linalg.svd(x)
    #可以打印
    print(np.linalg.svd(x))
    #第2步：根据占比阈值percentage，求k值
    #奇异值
    K = calc_k()
    print("奇异值个数为：",K)
    #第3步：根据求得的k构造k阶奇异值对角阵
    SD = buildSD(K)
    print("奇异值的对角矩阵",SD)

    #第4步：构建新的U和V
    new_U = U[:len(U),:K]
    new_V = V[:K, :len(V)]
    print("new_U",new_U)
    print("new_V",new_V)

    new_M = np.dot(np.dot(new_U,SD),new_V)
    print("x原始结果：")
    print(x)
    print("SVD降维结果：")
    print(new_M)




